package connect

import (
	"context"
	"crypto/tls"
	"net"
	"net/http"
	"net/url"
	"time"

	"github.com/go-kratos/kratos/v2/log"
	"github.com/go-kratos/kratos/v2/transport"
)

var (
	_ transport.Server     = (*Server)(nil)
	_ transport.Endpointer = (*Server)(nil)
)

type Server struct {
	lis      net.Listener   // 监听器，用于接受客户端的连接请求
	network  string         // 协议
	addr     string         // 监听地址
	endpoint *url.URL       // 服务端点信息
	timeout  time.Duration  // 超时时间
	tlsConf  *tls.Config    // tls配置
	err      error          // 错误信息
	httpSrv  *http.Server   // HTTP服务器
	mux      *http.ServeMux // 路由复用器
}

func NewServer(opts ...ServerOption) *Server {
	srv := &Server{
		network: "tcp",
		addr:    ":0",
		mux:     http.NewServeMux(),
	}
	for _, o := range opts {
		o(srv)
	}
	return srv
}

func (s *Server) Start(ctx context.Context) error {
	if err := s.listenAndEndpoint(); err != nil {
		return err
	}
	s.httpSrv = &http.Server{
		Handler:   s.mux,
		TLSConfig: s.tlsConf,
	}
	go func() {
		if s.tlsConf != nil {
			if err := s.httpSrv.ServeTLS(s.lis, "", ""); err != nil && err != http.ErrServerClosed {
				log.Errorf("[Connect] failed to serve: %v", err)
			}
		} else {
			if err := s.httpSrv.Serve(s.lis); err != nil && err != http.ErrServerClosed {
				log.Errorf("[Connect] failed to serve: %v", err)
			}
		}
	}()
	log.Infof("[Connect] server listening on: %s", s.lis.Addr().String())
	return nil
}

func (s *Server) Stop(ctx context.Context) error {
	if s.httpSrv != nil {
		return s.httpSrv.Shutdown(ctx)
	}
	if s.lis != nil {
		return s.lis.Close()
	}
	return nil
}

// 监听并获取服务端点信息
func (s *Server) listenAndEndpoint() error {
	if s.lis == nil {
		lis, err := net.Listen(s.network, s.addr)
		if err != nil {
			s.err = err
			return err
		}
		s.lis = lis
	}
	if s.endpoint == nil {
		addr, err := Extract(s.addr, s.lis)
		if err != nil {
			s.err = err
			return err
		}
		s.endpoint = NewEndpoint(Scheme("Connect", s.tlsConf != nil), addr)
	}
	return s.err
}

func (s *Server) Endpoint() (*url.URL, error) {
	if err := s.listenAndEndpoint(); err != nil {
		return nil, err
	}
	return s.endpoint, nil
}

type ServerOption func(*Server)

func Network(network string) ServerOption {
	return func(s *Server) {
		s.network = network
	}
}

func Address(addr string) ServerOption {
	return func(s *Server) {
		s.addr = addr
	}
}

func TLSConfig(c *tls.Config) ServerOption {
	return func(s *Server) {
		s.tlsConf = c
	}
}

func Timeout(timeout time.Duration) ServerOption {
	return func(s *Server) {
		s.timeout = timeout
	}
}

// Handle 注册HTTP处理器到指定路径
func (s *Server) Handle(path string, handler http.Handler) {
	s.mux.Handle(path, handler)
}
